import datetime
import os
import re
import oss2
from django.db.models import Sum, Max
from django.shortcuts import render
from rest_framework.response import Response

from appeal.models import Appeals
from bilimili_django import settings
from column.models import Column
from column.serializer import ColumnSerializer
from comment.models import Comment
from complaint.models import Complaints
from favor.models import Favor
from follow.models import Follow
from like.models import Like
from play.models import Play
from video_reviewing.models import VideosReviewing
from .models import Videos
from .serializer import VideosSerializer, VideosDetailSerializer
from rest_framework import viewsets, mixins, status

from django.core.files.storage import default_storage
from django.core.files.base import ContentFile
from PIL import Image
from moviepy.editor import VideoFileClip


# Create your views here.
class VideosViewSet(viewsets.ModelViewSet):
    serializer_class = VideosSerializer

    def get_queryset(self):
        queryset = Videos.objects.all()
        params = self.request.query_params
        if params:
            filters = {}
            for key, value in params.items():
                filters[key] = value
            queryset = queryset.filter(**filters)
        return queryset

    def get_column_favor(self, request, *args, **kwargs):
        coid = kwargs.get('coid')
        user = kwargs.get('user')
        videos = Videos.objects.filter(column=coid).filter(status=True)
        favors = Favor.objects.filter(video_id__in=videos).filter(user_id=user).filter(is_active=True)
        if len(favors) == len(videos):
            all_favored = True
        else:
            all_favored = False
        result = []
        for video in videos:
            result.append(VideosSerializer(video).data)
        return Response({'result': result, 'all_favored': all_favored}, status=status.HTTP_200_OK)

    def post_video_inspect(self, request, *args, **kwargs):
        filename = request.data.get('name')
        target_path = os.path.join(settings.MEDIA_ROOT, 'videos/temp', filename)
        if os.path.exists(target_path):
            file_count = len(
                [f for f in os.listdir(str(target_path)) if os.path.isfile(os.path.join(str(target_path), f))])
        else:
            file_count = 0
        return Response({'index': file_count}, status=status.HTTP_200_OK)

    def post_video_slice(self, request, *args, **kwargs):
        index = int(request.data.get('index'))
        file = request.data.get('file')
        filename = request.data.get('filename')
        if file and filename and index is not None:
            index = int(index)
            temp_dir = os.path.join(settings.MEDIA_ROOT, 'videos/temp', filename)
            if not os.path.exists(temp_dir):
                os.makedirs(temp_dir)
            default_storage.save(f'{temp_dir}/{filename}_chunk{index}', ContentFile(file.read()))

            return Response({"message": "Chunk uploaded successfully"}, status=status.HTTP_200_OK)

        return Response({"error": "Invalid request"}, status=status.HTTP_400_BAD_REQUEST)

    def post_video_merge(self, request, *args, **kwargs):
        filename = request.data.get('fileName')
        fileType = request.data.get('fileType')
        title = request.data.get('title')
        tags = request.data.get('tags')
        user_id = request.data.get('user')
        type = request.data.get('type')
        description = request.data.get('description')
        if(not filename or not user_id):
            return Response({'message': 'illegal request'}, status=status.HTTP_400_BAD_REQUEST)
        if Videos.objects.all().count() == 0:
            max_id = 'miv000000'
        else:
            max_id = Videos.objects.all().order_by('-vid')[0].vid
        new_id = increment_string(max_id)
        temp_dir = os.path.join(settings.MEDIA_ROOT, 'videos/temp', filename)
        chunk_paths = [os.path.join(str(temp_dir), f"{filename}_chunk{i}") for i in
                       range(len(os.listdir(str(temp_dir))))]
        video_output_path = os.path.join(settings.MEDIA_ROOT, 'videos', f"{new_id}.{fileType}")
        # 读取文件夹中文件个数并生成path加入chunk_path数组
        with open(video_output_path, 'wb') as output_file:
            for chunk_path in chunk_paths:
                with open(chunk_path, 'rb') as chunk_file:
                    output_file.write(chunk_file.read())

        cover_output_path = settings.MEDIA_ROOT + '/imgs/covers/' + new_id + '.png'
        duration = extract_first_frame(video_output_path, cover_output_path)
        bucket = oss2.Bucket(settings.AUTH, settings.OSS_WRITE_ROOT, 'bilimili2')
        bucket.put_object_from_file(f"videos/{new_id}.{fileType}", video_output_path)
        bucket.put_object_from_file(f"imgs/covers/{new_id}.png", cover_output_path)
        try:
            os.remove(cover_output_path)
        except:
            pass
        try:
            os.remove(video_output_path)
        except:
            pass
        # 清理临时目录
        for chunk_path in chunk_paths:
            os.remove(chunk_path)
        os.rmdir(temp_dir)




        file_path = settings.OSS_READ_ROOT + f"/videos/{new_id}.{fileType}"
        cover_path = settings.OSS_READ_ROOT + '/imgs/covers/' + new_id + '.png'
        Videos.objects.create(
            vid=new_id,
            file_path=file_path,
            duration=duration,
            title=title,
            cover_path=cover_path,
            tags=tags,
            type=type,
            description=description,
            mup_id=user_id,
            status=False,
        )
        VideosReviewing.objects.create(
            file_path=file_path,
            duration=duration,
            title=title,
            cover_path=cover_path,
            tags=tags,
            type=type,
            description=description,
            status=None,
            mup_id=user_id,
            video_id=new_id
        )
        Play.objects.create(
            user_id=1,
            video_id=new_id,
            count=0,
            progress=0,
        )
        return Response({"message": "Video chunks merged successfully"}, status=status.HTTP_200_OK)

    def get_strange(self, request, *args, **kwargs):
        user_id = kwargs['user']
        videos = Videos.objects.filter(mup_id=user_id).filter(status=False).order_by('-update_time')
        columns = Column.objects.filter(mup_id=user_id).filter(status=False).order_by('-update_time')
        results = []
        for video in videos:
            review_status = VideosReviewing.objects.filter(video_id=video.vid)[0].status
            appeal_status = len(Appeals.objects.filter(video_id=video.vid).filter(type='1'))
            appeal_finish_status = len(Appeals.objects.filter(video_id=video).filter(type='3'))
            complaint_status = len(Complaints.objects.filter(video_id=video.vid).filter(type='3'))
            results.append(VideosSerializer(video).data)
            if review_status is None:
                results[-1].update(status='审核中')
            elif not review_status:
                results[-1].update(status='未通过')
            elif appeal_finish_status > 0:
                results[-1].update(status='申诉失败')
            elif appeal_status == 0 and complaint_status == 0:
                results[-1].update(status='已删除')
            elif appeal_status == 0 and complaint_status > 0:
                results[-1].update(status='举报下架')

            elif appeal_status > 0:
                results[-1].update(status='申诉中')
        for column in columns:
            appeal_status = len(Appeals.objects.filter(column_id=column.coid).filter(type='2'))
            appeal_finish_status = len(Appeals.objects.filter(column_id=column).filter(type='3'))
            complaint_status = len(Complaints.objects.filter(column_id=column.coid).filter(type='3'))
            results.append(ColumnSerializer(column).data)
            if appeal_finish_status > 0:
                results[-1].update(status='申诉失败')
            elif appeal_status == 0 and complaint_status == 0:
                results[-1].update(status='已删除')
            elif appeal_status == 0 and complaint_status > 0:
                results[-1].update(status='举报下架')
            elif appeal_status > 0:
                results[-1].update(status='申诉中')

        return Response(results, status=status.HTTP_200_OK)


class VideosDetailViewSet(viewsets.ModelViewSet):
    serializer_class = VideosDetailSerializer

    def get_queryset(self):
        queryset = Videos.objects.all()
        params = self.request.query_params
        if params:
            filters = {}
            for key, value in params.items():
                filters[key] = value
            queryset = queryset.filter(**filters)

        return queryset

    def get_dynamic(self, request, *args, **kwargs):
        user = kwargs.get('user')
        num = kwargs.get('num')
        from_index = kwargs.get('from')
        mup = kwargs.get('mup')
        if mup == 0:
            m_ups = Follow.objects.filter(fan=user).filter(is_active=True)
        else:
            m_ups = Follow.objects.filter(fan=user, mup=mup).filter(is_active=True)

        dynamics = []
        results = []
        render_red = 0
        last_dates = {}
        count = 0
        index = 0
        for m_up in m_ups:
            last_dates.update({m_up.mup.id: m_up.dynamic_last_time})
            videos = Videos.objects.filter(mup=m_up.mup).filter(status=True).order_by('-update_time')
            count += len(videos)
            for video in videos:
                dynamics.append(VideosDetailSerializer(video).data)
                dynamics[-1].update(update_time=video.update_time)

        dynamics.sort(key=lambda x: x['update_time'], reverse=True)

        for dynamic in dynamics:
            if index < from_index:
                index += 1
                continue
            if index >= from_index + num:
                break
            if dynamic.get('update_time') > last_dates.get(dynamic.get('mup').get('id')):
                render_red += 1
            plays = Play.objects.filter(video_id=dynamic.get('vid')).aggregate(sum_plays=Sum('count'))['sum_plays']
            likes = Like.objects.filter(video_id=dynamic.get('vid')).count()
            favors = Favor.objects.filter(video_id=dynamic.get('vid')).count()
            comments = Comment.objects.filter(video_id=dynamic.get('vid')).count()
            dynamic.update({'plays': plays, 'likes': likes, 'favors': favors, 'comments': comments})
            results.append(dynamic)
            index += 1

        return Response({"dynamics": results, "render_red": render_red, "count": count}, status=status.HTTP_200_OK)

    def get_profile(self, request, *args, **kwargs):
        mup = kwargs.get('mup')
        from_index = kwargs.get('from')
        num = kwargs.get('num')
        type = kwargs.get('type')
        if type == 0:
            data, count = getProfileVideo(mup, from_index, num)
        else:
            data, count = getProfileColumn(mup, from_index, num)

        return Response({"data": data, "count": count}, status=status.HTTP_200_OK)

    def get_related(self, request, *args, **kwargs):
        v_type = kwargs.get('type')
        videos = Videos.objects.filter(type=v_type).filter(status=True)
        result = []
        for video in videos:
            this_video = VideosDetailSerializer(video).data
            sum_plays = Play.objects.filter(video_id=video.vid).aggregate(sum_plays=Sum('count'))['sum_plays']
            this_video['sum_plays'] = sum_plays
            time = this_video['update_time']
            this_video['update_time'] = video.update_time.date()
            result.append(this_video)
        result.sort(key=lambda x: x['sum_plays'], reverse=True)
        return Response(result, status=status.HTTP_200_OK)


def extract_first_frame(video_path, output_image_path):
    # 加载视频文件
    clip = VideoFileClip(video_path)
    frame = clip.get_frame(0)  # 0表示视频的开始时间，即第一帧
    duration = clip.duration
    clip.close()  # 关闭clip以释放资源
    Image.fromarray(frame).save(output_image_path)
    return duration


def increment_string(s):
    # 使用正则表达式匹配字符串中的数字部分
    match = re.search(r'(\d+)$', s)
    # 提取数字部分并加一
    number = int(match.group(1)) + 1
    # 使用字符串格式化将数字部分格式化为与原数字相同长度的字符串
    incremented_number = str(number).zfill(len(match.group(1)))
    # 将原字符串中的数字部分替换为新的数字部分
    result = re.sub(r'\d+$', incremented_number, s)
    return result


def getProfileVideo(mup, from_index, num):
    videos = Videos.objects.filter(mup=mup).filter(status=True).order_by('-update_time')
    plays = Play.objects.filter(video__in=videos)
    likes = Like.objects.filter(video_id__in=videos)
    result = []
    for i in range(from_index, min(from_index + num, len(videos))):
        video = videos[i]
        this_video = VideosSerializer(video).data
        this_plays = plays.filter(video_id=video).aggregate(sum_plays=Sum('count'))['sum_plays']
        this_likes = likes.filter(video_id=video).count()
        this_video.update(play_count=this_plays)
        this_video.update(like_count=this_likes)
        result.append(this_video)
    return result, len(videos)


def getProfileColumn(mup, from_index, num):
    columns = Column.objects.filter(mup=mup).filter(status=True).order_by('-update_time')
    result = []
    for i in range(from_index, min(from_index + num, len(columns))):
        column = columns[i]
        this_column = ColumnSerializer(column).data
        result.append(this_column)
    return result, len(columns)
